using System;
using System.Collections.Generic;
using System.Diagnostics;
using TAAlert.CommonUtils;

namespace TAAlert.BackTest
{
    /// <summary>Volatility driven EMA strategy. For volatilites below treshold use period nEMA1, for volatilities above treshold use periods nEMA2 (or stary neutral</summary>
    class VEMAStrategy : Strategy
    {
        #region Private Members
        static private readonly TraceSwitch traceM = new TraceSwitch("VEMAStrategy", "Debug info for Strategy class");

        private List<double> ema1M = new List<double>();     // exp moving average. Used for vol below treashold
        private List<double> ema2M = new List<double>();     // exp moving average. Used for volatilities above treashold (or not at all if nEMA2=0  
        private int nEMA1M;             // eMA period for vol below treashold
        private int nEMA2M;             // EMA period for vol above treashold
        private List<double> volM;      // valitility array
        private double volTreasholdM;   // Treashold volatility. Use nEMA1 for vol < volT and nEMA2 for vol>volT
        #endregion

        /// <summary>Constructor of Volatility driven EMA strategy</summary>
        /// <param name="nEMA1">period of EMA used below treashold volatility</param>
        /// <param name="nEMA2">period of EMA used above treashold volatility. If nEMA2=0 then stay neutral above treashold</param>
        /// <param name="volTreashold">Volatility treashold. Use nEMA1 below and nEMA2 above</param>
        public VEMAStrategy(int nEMA1, int nEMA2, double volTreashold, DateTime startDate, DateTime endDate, SortedList<DateTime, double> prices)
            : base(startDate, endDate, prices, traceM)
        {
            Debug.WriteLineIf(traceM.TraceInfo, "--> Entering VEMAStrategy(n1=" + nEMA1 + ", n2=" + nEMA2 + ", volT=" + volTreashold + ", " + startDate.ToShortDateString() + ", " + endDate.ToShortDateString() + ", prices)");
            // calculate EMAs
            this.nEMA1M = nEMA1;
            this.nEMA2M = nEMA2;
            if (this.nEMA1M > 0)
                this.ema1M = EMAEvaluator.calcEMAArray(this.Prices.Values, this.nEMA1M);
            if (this.nEMA2M > 0)
                this.ema2M = EMAEvaluator.calcEMAArray(this.Prices.Values, this.nEMA2M);

            this.volM = EMAEvaluator.calcEMAVolatilityArray(this.Prices.Values); 
            this.volTreasholdM = volTreashold;
        }

        /// <summary>Generate list of investment positions. (+1 long, -1 short, 0 neutral)</summary>
        /// <returns>List of dated positions. The positions are established on date close and affect only the next day performance.</returns>
        override public SortedList<DateTime, int> generate()
        {
            Debug.WriteLineIf(traceM.TraceInfo, "--> Entering VEMAStrategy.generate()");
            Debug.Indent();
            int n = this.EndIx - this.StartIx + 1;

            SortedList<DateTime, int> pos = new SortedList<DateTime, int>(n);
            Debug.WriteLineIf(traceM.TraceVerbose, "ix,Date,Price,vol,EMA1,EMA2,Position");
            for (int ix = this.StartIx; ix <= this.EndIx; ++ix)
            {
                DateTime date = this.Prices.Keys[ix];
                double vol = this.volM[ix];
                double price = this.Prices.Values[ix];
                double ema1 = (this.nEMA1M>0 ? this.ema1M[ix] : 0);
                double ema2 = (this.nEMA2M>0 ? this.ema2M[ix] : 0);

                int signal = (int)EMAEvaluator.vemaSignal(price, vol, this.nEMA1M, ema1, this.nEMA2M, ema2, this.volTreasholdM);

                pos.Add(date, signal);
                Debug.WriteLineIf(traceM.TraceVerbose, ix + "," + date.ToShortDateString() + "," + this.Prices.Values[ix].ToString("N2") + "," + vol.ToString("N2") + "," +
                    (this.nEMA1M > 0 ? this.ema1M[ix] : 0).ToString("N2") + "," + (this.nEMA2M > 0 ? this.ema2M[ix] : 0).ToString("N2") + "," + signal);
            }
            Debug.WriteLineIf(traceM.TraceInfo, "... generated " + pos.Count + " signals");

            Debug.Unindent();
            return pos;
        }
    }
}
